/* eslint-disable */
import Layers from "../../lang/layers";
import Asserts from "../core/asserts";
import FormInput from "./form-input";

/**
 * 默认的触发器
 *
 * 一个全局的 change() 事件
 *
 * @param name  字段名
 * @param value 值
 */
const trigger = (name, value) => {
    // do nothing...
}


/**
 * 表单组
 *
 * 内部已经包含完整的调用逻辑，只需要根据提供的数据，渲染界面即可。
 *
 * 设计思路，类似于后台的 MVC 模式，form-model => form-input => view；
 */
class FastForm {
    /**
     * form-input 列表
     *
     * @type {[FormInput]}
     */
    group: FormInput[];

    /**
     * 验证规则，表单数据的校验规则
     *
     * @type {{}}
     */
    rules: {};

    /**
     * 风格主题
     *
     * 组件会根据这个值，进行不同的风格绘制，常见的，就是水平布局和垂直布局
     *
     * @type {string}
     */
    theme: string;
    /**
     * 表单初始值
     *
     * @type {{}}
     */
    defaultValue: {}

    /**
     * 值变化触发器
     *
     * 如果有必要，子组件可以通过当前函数，通知到表单主体
     * （暂时取消这一设计）
     *
     * @type {function}
     * @param name  键
     * @param value 值
     */
    trigger: Function;

    /**
     * 根据数据模型，创建一个表单对象
     *
     * @param models {{}|[]}
     */
    constructor(models: any | any[]) {
        this.group = [];
        this.rules = {}
        this.theme = '';
        this.defaultValue = {}
        this.trigger = trigger;

        // 根据数据模型，转换成 FormInput 列表
        if (models !== undefined) {
            this.setModels(models);
        }
    }

    /**
     * 整个表单的 change() 事件
     *
     * @param listener {function} 侦听函数
     */
    setValueChangeListener(listener) {
        Asserts.isTypeOf(listener, 'function', 'listener is not a function!')
        this.trigger = listener
    }

    /**
     * 设置对象模型
     *
     * @param models {{}|[]} 允许是对象或者数组
     */
    setModels(models) {
        let ret = [];

        if (Array.isArray(models)) {
            // 表单模型树一个数组
            models.forEach(item => {
                const input = new FormInput();

                // 复制同名字段到 input
                input.from(item);

                // 所属表单
                input.form = this;
                // 风格主题
                input.theme = this.theme;

                ret.push(input);

                // 表单校验规则
                if (input.rules !== undefined) {
                    this.rules[input.name] = input.rules;
                }

                // 默认值
                if (input.value !== undefined) {
                    this.defaultValue[input.name] = input.value;
                }
            });
        } else {
            // 表单模型是一个对象
            for (let key in models) {
                if (models.hasOwnProperty(key)) {
                    const input = new FormInput();

                    input.form = this;

                    input.name = key;
                    input.value = models[key];

                    ret.push(input);

                    // 默认值
                    if (input.value !== undefined) {
                        this.defaultValue[input.name] = input.value;
                    }
                }
            }
        }
        this.group = ret;
    }


    /**
     * 获取所有输入框对象实例
     *
     * @returns {[FormInput]} 实例列表
     */
    getFormInputs() {
        return this.group;
    }

    /**
     * 获取表单输入框实例
     *
     * @param name 输入框名称
     * @returns {FormInput} 实例
     */
    getFormInput(name) {
        for (let i = 0; i < this.group.length; i++) {
            if (name === this.group[i].name) {
                return this.group[i];
            }
        }
        throw new NullPointerException('form input is undefined:' + name);
    }

    /**
     * 覆盖表单数值
     *
     * 设值过程中，会触发 change() 事件；未指定的值，仍然使用之前的值。
     *
     * @param obj {{}} 对象
     */
    recover(obj) {
        //根据序列化之后的值，进行数据恢复
        for (let i = 0; i < this.group.length; i++) {
            let input = this.group[i];
            let val = obj[input.name];
            if (val !== undefined && input.value !== val) {
                input.changeValue(val);
            }
        }
    }

    /**
     * 表单设值
     *
     * 设值过程中，会触发 change() 事件；未指定的值，会用缺省值替换。
     *
     * @param obj {{}} 对象
     */
    val(obj) {
        for (let i = 0; i < this.group.length; i++) {
            let input = this.group[i];
            if (input.active) {
                let val = obj[input.name];
                if (val === undefined) {
                    val = input.defaultValue;
                }
                if (input.value !== val) {
                    input.changeValue(val);
                }
            }
        }
    }

    /**
     * 设置新的表单数值
     *
     * 但是不触发监听事件
     */
    setValue(name, value) {
        let input = this.getFormInput(name);
        input.setValue(value);
    }

    /**
     * 设置新的表单数值
     *
     * 但是不触发监听事件
     */
    changeValue(name, value) {
        let input = this.getFormInput(name);
        input.changeValue(value);
    }

    /**
     * 设置初始值
     *
     * @param obj
     */
    setDefaultValue(obj) {
        this.defaultValue = obj;
    }

    /**
     * 重置表单
     */
    reset() {
        this.val(this.defaultValue);
    }

    /**
     * 置空表单
     */
    clear() {
        for (let i = 0; i < this.group.length; i++) {
            this.group[i].clear();
        }
    }

    /**
     * 设置校验规则
     *
     * @param rules {{}}
     */
    setRules(rules) {
        this.rules = rules;
    }

    /**
     * 配置一个字段的校验规则
     *
     * @param name {String} 字段名
     * @param rules {{}} 校验规则
     */
    putRules(name, rules) {
        this.rules[name] = rules;
    }

    /**
     * 用户输入是否满足校验规则
     *
     * @returns {boolean} if true
     */
    isValid() {
        for (let i = 0; i < this.group.length; i++) {
            let ele = this.group[i];
            // 如果isValid未定义，则说明没用到表单验证，直接校验通过
            if (!ele.isValid()) {
                console.error('invalid: ' + ele.label);
                console.error('invalid: ' + ele.message);
                return false;
            }
        }
        return true;
    }


    /**
     * 序列化表单
     *
     * @returns {{}} 表单数值
     */
    serialize() {
        let res = {};
        for (let i = 0; i < this.group.length; i++) {
            let input = this.group[i];
            let val = input.getValue();

            // 序列化结果过滤无意义的值
            if (Layers.isNotEmpty(val)) {
                res[input.name] = val;
            }
        }
        return res;
    }

    /**
     * 序列化表单
     *
     * @returns {FormData} 表单数值
     */
    formData() {
        let res = new FormData();
        for (let i = 0; i < this.group.length; i++) {
            let input = this.group[i];
            let val = input.getValue();

            // 序列化结果过滤无意义的值
            if (Layers.isNotEmpty(val)) {
                res.append(input.name, val);
            }
        }
        return res;
    }
}

export default FastForm;